package com.virtualCat.service.impl;

import com.virtualCat.common.*;
import com.virtualCat.dao.CatDao;
import com.virtualCat.dao.FeedDao;
import com.virtualCat.dao.PayOrderDao;
import com.virtualCat.dao.UserDao;
import com.virtualCat.entity.Cat;
import com.virtualCat.entity.Feed;
import com.virtualCat.entity.PayOrder;
import com.virtualCat.service.WeChatPayService;
import com.virtualCat.util.HttpUtil;
import com.virtualCat.util.WeChatPayUtil;
import com.virtualCat.vo.WxPayReturnData;
import com.virtualCat.vo.WxPaySendData;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.DataOutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

@Service
public class WeChatPayServiceImpl implements WeChatPayService {
    @Autowired
    CatDao catDao;

    @Autowired
    PayOrderDao payOrderDao;

    @Autowired
    UserDao userDao;

    @Autowired
    FeedDao feedDao;

    private static org.slf4j.Logger log = LoggerFactory.getLogger(WeChatPayServiceImpl.class);

    /**
     * 统一下单
     * @param map
     * @return
     */
    public Msg unifiedOrder(Map<String,Object> map) {
        int cat_id=Integer.valueOf(map.get("cat_id").toString());
        Cat cat = catDao.findById(cat_id);
        if (cat == null){
            return Msg.fail().add("喵咪id错误","11202");
        }
        int resultCount = userDao.selectUserByOpenid(map.get("openid").toString());
        if (resultCount == 0){
            return Msg.fail().add("用户不存在","11203");
        }
        Map<String,String> reqMap = new HashMap<String, String>();
        reqMap.put("appid", WeChatConfig.APP_ID);
        reqMap.put("mch_id",WeChatConfig.MCH_ID);
        reqMap.put("nonce_str", WXPayUtil.generateNonceStr());
        reqMap.put("body",cat.getCname());
        String orderId = UUID.randomUUID().toString().replace("-","");
        reqMap.put("out_trade_no",orderId);
        BigDecimal n_price = new BigDecimal(cat.getNprice());
        BigDecimal bd = new BigDecimal("100");
        String fen_price = n_price.setScale(2,BigDecimal.ROUND_HALF_UP).multiply(bd).setScale(0).toString();
        reqMap.put("total_fee",fen_price);
        reqMap.put("spbill_create_ip",WeChatConfig.REMOTE_IP);
        reqMap.put("notify_url",WeChatConfig.NOTIFY_URL);
        reqMap.put("trade_type",WeChatConfig.TRADE_TYPE_JSAPI);
        reqMap.put("openid",map.get("openid").toString());
        String reqXml ="";
        try {
            String sign = WXPayUtil.generateSignature(reqMap,WeChatConfig.KEY);
            reqMap.put("sign",sign);
            reqXml = WXPayUtil.mapToXml(reqMap);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //**************************************//
        //生成自己的下单数据表
        PayOrder payOrder =new PayOrder(orderId,(String) map.get("openid"),
                Integer.parseInt((String)map.get("cat_id")),
                cat.getNprice(),cat.getCname(),new Date(),Const.OrderType.NO_PAY.getCode());
        int rowCount = payOrderDao.insert(payOrder);
        if (rowCount == 0){
            return Msg.fail().add("payorder_fail",11204);
        }
        //**************************************//

        try {
            Map<String,String> resultMap=WXPayUtil.xmlToMap(HttpUtil.doPost(WeChatConfig.UNIFIED_ORDER_URL,reqXml)) ;
            log.info("resultMap\n"+resultMap);
            String returnCode = resultMap.get("return_code");//通信标识
            String resultCode = resultMap.get("result_code");//交易标识
            log.info("result_code"+resultCode);
            //只有当returnCode与resultCode均返回“success”，才代表微信支付统一下单成功
            if (WeChatConstant.RETURN_SUCCESS.equals(resultCode)&&
                    WeChatConstant.RETURN_SUCCESS.equals(returnCode)){
                String timeStamp = WeChatPayUtil.getTimeStamp();//当前时间戳
                String appId = resultMap.get("appid");//微信公众号AppId
                String prepayId = "prepay_id="+resultMap.get("prepay_id");//统一下单返回的预支付id
                String nonceStr = WeChatPayUtil.getRandomStr(20);//不长于32位的随机字符串
                Map<String,String> signMap = new HashMap<String, String>();
                signMap.put("appId",appId);
                signMap.put("package",prepayId);
                signMap.put("timeStamp",timeStamp);
                signMap.put("nonceStr",nonceStr);
                signMap.put("signType","MD5");
                WxPayReturnData returnData=new WxPayReturnData();
                returnData.setAppid(appId);
                returnData.setTimeStamp(timeStamp);
                returnData.setNonceStr(nonceStr);
                returnData.setPrepay_id(prepayId);
                returnData.setSignType("MD5");
                returnData.setPaySign(WXPayUtil.generateSignature(signMap,WeChatConfig.KEY));
                return Msg.success().add("return_param",returnData).add("pay_order",orderId);
            }else {
                log.error("微信统一下单失败,订单编号:"+resultMap.get("out_trade_no")+",失败原因:"+resultMap.get("err_code_des"));
                return Msg.fail().add("error",resultMap.get("err_code_des"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Msg.fail().add("error","payException");
    }

    /**
     * 微信异步回调
     * @param request
     * @param response
     * @return
     */
    public Msg weiXinReceive(HttpServletRequest request, HttpServletResponse response) {
        log.info("======开始进入支付回调方法======");
        String xml_review_result = WeChatPayUtil.getXmlRequest(request);
        log.info("微信支付结果:\n"+xml_review_result);
        Map resultMap = null;
        try {
            resultMap = WXPayUtil.xmlToMap(xml_review_result);
            log.info("resultMap:\n"+resultMap);
            if(resultMap != null && resultMap.size() > 0){
                String sign_receive = (String)resultMap.get("sign");
                log.info("sign_receive:"+sign_receive);
                resultMap.remove("sign");
                String checkSign = WeChatPayUtil.getSign(resultMap, WeChatConfig.KEY);
                log.info("checkSign:"+checkSign);

                //签名校验成功
                if(checkSign != null && sign_receive != null &&
                        checkSign.equals(sign_receive.trim())){
                    log.info("check Sign SUCCESS");
                    try{
                        //获得返回结果
                        String return_code = (String)resultMap.get("return_code");
                        log.info("return_code:"+return_code);
                        if("SUCCESS".equals(return_code)){
                            String out_trade_no = (String)resultMap.get("out_trade_no");

                            //**********************************************//
                            //处理支付成功以后的逻辑，处理订单
                            PayOrder payOrder = payOrderDao.findById(out_trade_no);
                            if (payOrder == null){
                                log.info("订单号错误");
                            }
                            //todo 判断金额是否一致
                            int return_fee = Integer.valueOf(resultMap.get("total_fee").toString());
                            int sql_fee = (int) (payOrder.getTotal_fee()*100);
                            if (return_fee != sql_fee){
                                return null;
                            }
                            if(payOrder.getStatus() == Const.OrderType.NO_PAY.getCode()){
                                Feed feed =new Feed(payOrder.getOpenid(),payOrder.getCatid(),0,getNextDay(new Date()),0,0,0);
                                int resultCount = feedDao.insert(feed);
                                if (resultCount < 0){
                                    //todo 调用退款接口
                                    log.info("后台处理失败");
                                }
                                payOrderDao.update(Const.OrderType.PAID.getCode(),out_trade_no);
                            }
                            //**********************************************//

                            String checkXml = "<xml><return_code><![CDATA[OK]]></return_code></xml>";
                            ResultResponse(checkXml,"http://weixin.xinfor.com/wx/notifyUrl");
                        }else{
                            Msg.fail().add("err_code_des","fail");
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }else{
                    //签名校验失败
                    log.info("wei_xin receive check Sign fail");
                    String checkXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"+
                            "<return_msg><![CDATA[check sign fail]]></return_msg></xml>";
                  ResultResponse(checkXml,"http://weixin.xinfor.com/wx/notifyUrl");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询订单
     * @return
     */
    public Msg toWXPaySuccess(String  pay_id){
        int resultCount = payOrderDao.selectById(pay_id);
        if (resultCount == 0){
            return Msg.fail().add("订单号不存在",11301);
        }
        try {
            Map resultMap = checkWxOrderPay(pay_id);
            log.info(resultMap.toString());
            String return_code = (String)resultMap.get("return_code");
            String result_code = (String)resultMap.get("result_code");
            if("SUCCESS".equals(return_code)){
                if("SUCCESS".equals(result_code)){
                    String tradeStatus = (String) resultMap.get("trade_state");
                    if(Const.TradeStatus.SUCCESS.equals(tradeStatus)){
                        PayOrder payOrder = payOrderDao.findById(pay_id);
                        if (payOrder == null){
                            return Msg.fail().add("pay_order not found",11302);
                        }
                        Cat cat = catDao.findById(payOrder.getCatid());
                        if (cat == null){
                            return Msg.fail().add("cat not found",11303);
                        }
                        if(payOrder.getStatus() == Const.OrderType.NO_PAY.getCode()){//未支付
                            log.info("开始处理支付后的结果");
                            int rowCount = feedDao.checkByOpenid(payOrder.getOpenid());
                            if (rowCount > 0){
                                feedDao.deleteFeed(feedDao.findByOpenid(payOrder.getOpenid()).getOpenid());
                            }
                            Feed feed = new Feed(payOrder.getOpenid(),cat.getCatid(),0,getNextDay(new Date()),
                                    0,0,0);
                            resultCount = feedDao.insert(feed);
                            if (resultCount == 0){
                                payOrderDao.update(Const.OrderType.REFUND_WAIT.getCode(),payOrder.getOrderid());
                                boolean response = doRefund(payOrder.getOrderid(),resultMap.get("total_fee").toString());
                                if (response){
                                    return Msg.fail().add("无法生成猫咪，申请退款",11304);
                                }
                                return Msg.fail().add("insert feed fail",11305);
                            }
                            payOrderDao.update(Const.OrderType.PAID.getCode(),payOrder.getOrderid());
                        }
                        return Msg.success().add("pay_id",pay_id).add("payResult",true);
                    }else if(Const.TradeStatus.NOTPAY.equals(tradeStatus)){
                        return Msg.fail().add("未支付","not_pay");
                    }else if(Const.TradeStatus.REFUND.equals(tradeStatus)){
                        return Msg.fail().add("转为退款","refund");
                    }
                }else{
                    return Msg.fail().add("err_code","业务失败");
                }
            }else{
                return Msg.fail().add("payResult",false).add("err_code_des","通信错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map checkWxOrderPay(String orderId){
        Map<String,String> reqMap = new HashMap<String, String>();
        reqMap.put("appid",WeChatConfig.APP_ID);
        reqMap.put("mch_id",WeChatConfig.MCH_ID);
        reqMap.put("nonce_str",WXPayUtil.generateNonceStr());
        reqMap.put("out_trade_no",orderId);
        String sign = null;
        String reqXml = null;
        try {
            sign = WXPayUtil.generateSignature(reqMap, WeChatConfig.KEY);
            reqMap.put("sign",sign);
            reqXml = WXPayUtil.mapToXml(reqMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String resultMsg = HttpUtil.doPost(WeChatConfig.QUERY_URL, reqXml);
        if(StringUtils.isNotBlank(resultMsg)){
            Map resultMap = null;
            try {
                resultMap = WXPayUtil.xmlToMap(resultMsg);
                if(resultMap != null && resultMap.size() > 0){
                    return resultMap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 退款
     */
    public boolean doRefund(String out_trade_no,String total_fee) {
        String xml = "";
        Map<String,String> reqMap = new HashMap<String, String>();
        try {
            HashMap<String, String> data = new HashMap<String, String>();
            data.put("appid",WeChatConfig.APP_ID);
            data.put("mch_id",WeChatConfig.MCH_ID);
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("out_trade_no", out_trade_no);
            data.put("out_refund_no", out_trade_no);
            data.put("total_fee", total_fee);
            data.put("refund_fee", total_fee);
            data.put("refund_fee_type", "CNY");
            data.put("op_user_id", WeChatConfig.MCH_ID);
            String sign = WXPayUtil.generateSignature(data,WeChatConfig.KEY);
            data.put("sign",sign);
            xml = WXPayUtil.mapToXml(data);
            String strResult = WXPayUtil.wxPayBack(WeChatConfig.REFUND_URL,xml);
            reqMap = WXPayUtil.xmlToMap(strResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String return_code = reqMap.get("return_code");
        String result_code = reqMap.get("result_code");
        if("SUCCESS".equals(return_code)) {
            if ("SUCCESS".equals(result_code)) {
                String out_refund_no = reqMap.get("out_refund_no");
                int rowCount = payOrderDao.update(Const.OrderType.REFUND_SUCCESS.getCode(), out_refund_no);
                if (rowCount == 0) {
                    log.info("订单" + out_refund_no + "更改失败");
                }
                return true;
            }
        }
        return false;
    }


//    private SortedMap<String,Object> buildParamMap(WxPaySendData data) {
//        SortedMap<String,Object> paramters = new TreeMap<String, Object>();
//        if (null != data){
//            if (StringUtils.isNotEmpty(data.getAppid())){
//                paramters.put("appid",data.getAppid());
//            }
//            if (StringUtils.isNotEmpty(data.getBody())){
//                paramters.put("body",data.getBody());
//            }
//            if (StringUtils.isNotEmpty(data.getDetail())){
//                paramters.put("detail",data.getDetail());
//            }
//            if (StringUtils.isNotEmpty(data.getDeviceInfo())){
//                paramters.put("device_info",data.getDeviceInfo());
//            }
//            if (StringUtils.isNotEmpty(data.getFeeType())){
//                paramters.put("fee_type",data.getFeeType());
//            }
//            if (StringUtils.isNotEmpty(data.getGoodsTag())){
//                paramters.put("goods_tag",data.getGoodsTag());
//            }
//            if (StringUtils.isNotEmpty(data.getLimitPay())){
//                paramters.put("limit_pay",data.getLimitPay());
//            }
//            if (StringUtils.isNotEmpty(data.getMchId())){
//                paramters.put("mch_id",data.getMchId());
//            }
//            if (StringUtils.isNotEmpty(data.getNonceStr())){
//                paramters.put("nonce_str",data.getNonceStr());
//            }
//            if (StringUtils.isNotEmpty(data.getNotifyUrl())){
//                paramters.put("notify_url",data.getNotifyUrl());
//            }
//            if (StringUtils.isNotEmpty(data.getOpenId())){
//                paramters.put("openid",data.getOpenId());
//            }
//            if (StringUtils.isNotEmpty(data.getOutTradeNo())){
//                paramters.put("out_trade_no",data.getOutTradeNo());
//            }
//            if (StringUtils.isNotEmpty(data.getSign())){
//                paramters.put("sign",data.getSign());
//            }
//            if (StringUtils.isNotEmpty(data.getSpBillCreateIp())){
//                paramters.put("spbill_create_ip",data.getSpBillCreateIp());
//            }
//            if (StringUtils.isNotEmpty(data.getTimeStart())){
//                paramters.put("time_start",data.getTimeStart());
//            }
//            if (StringUtils.isNotEmpty(data.getTimeExpire())){
//                paramters.put("time_expire",data.getTimeExpire());
//            }
//            if (StringUtils.isNotEmpty(data.getProductId())){
//                paramters.put("product_id",data.getProductId());
//            }
//            if (data.getTotalFee()>0){
//                paramters.put("total_fee",data.getTotalFee());
//            }
//            if (StringUtils.isNotEmpty(data.getTradeType())){
//                paramters.put("trade_type",data.getTradeType());
//            }
//            //申请退款参数
//            if (StringUtils.isNotEmpty(data.getTransactionId())){
//                paramters.put("transaction_id",data.getTransactionId());
//            }
//            if (StringUtils.isNotEmpty(data.getOutRefundNo())){
//                paramters.put("out_refund_no",data.getOutRefundNo());
//            }
//            if (StringUtils.isNotEmpty(data.getOpUserId())){
//                paramters.put("op_user_id",data.getOpUserId());
//            }
//            if (StringUtils.isNotEmpty(data.getRefundFeeType())){
//                paramters.put("refund_fee_type",data.getRefundFeeType());
//            }
//            if (null != data.getRefundFee() && data.getRefundFee()>0){
//                paramters.put("refund_fee",data.getRefundFee());
//            }
//        }
//        return paramters;
//    }


    private void ResultResponse(String responseXml,String urlConn){
        try {
            byte[] xmlData = responseXml.getBytes("UTF-8");
            URL url = new URL(urlConn);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.setRequestMethod("POST");
            urlConnection.setRequestProperty("Charset", "UTF-8");
            urlConnection.setRequestProperty("Connection", "Keep-Alive");
            urlConnection.setRequestProperty("Content_Type", "text/xml; charset=UTF-8");
            urlConnection.setRequestProperty("Content-length", String.valueOf(xmlData.length));
            DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
            outputStream.write(xmlData);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 构建统一下单参数map 用于生成签名
     * @param data
     * @return SortedMap<String,Object>
     */
    private SortedMap<String,Object> buildParamMap(WxPaySendData data) {
        SortedMap<String, Object> paramters = new TreeMap<String, Object>();
        if (null != data) {
            paramters.put("app  id", data.getAppid());
            paramters.put("mch_id", data.getMch_id());
            paramters.put("nonce_str", data.getNonce_str());
            paramters.put("body", data.getBody());
            paramters.put("out_trade_no", data.getOut_trade_no());
            paramters.put("total_fee", data.getTotal_fee());
            paramters.put("spbill_create_ip", data.getSpbill_create_ip());
            paramters.put("notify_url", data.getNotify_url());
            paramters.put("trade_type", data.getTrade_type());
            paramters.put("openid", data.getOpenid());
        }
        return paramters;
    }

    /**
     * 获得当前时间的前一天
     * @param date
     * @return
     */
    private Date getNextDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        date = calendar.getTime();
        return date;
    }
}
